from networkNode import NetworkNode
from optionServer import optionServer
from fileServer import fileServer
from eventServer import eventServer
from object import Object
import time

class NetworkServer(NetworkNode):
    def __init__(self):
        NetworkNode.__init__(self, optionServer.get('ip'), optionServer.get('port',1235))
        self.server = (optionServer.get('serverIp',self.ip),optionServer.get('serverPort',1234))
        
        self.objectNames = {}
        self.actionNames = {}
        self.rpcResults = {}
        self.requestedVars = set()
        
    def connect(self):
        self.connected = False
        print "connecting to server at", self.server
        self.send("reg",fileServer.modules)
        self.wait(lambda: self.send("reg",fileServer.modules), lambda: not self.connected)
    
    def send(self, cmd, msg, dest = None):
        NetworkNode.send(self, cmd, msg, dest or self.server)
        
    def wait(self, send, cond):
        start = time.time()
        while not Object.shutdown and cond():
            self.pump()
            if time.time() - start > optionServer.get('networkRetryTime',1):
                start = time.time()
                send()
        
    def kill(self):
        self.send("unreg",None)
        NetworkNode.kill(self)
        
    def receive_shutdown(self, msg, sender):
        print "received shutdown from server"
        Object.shutdown = True
        
    def receive_regAck(self, msg, sender):
        if not self.connected:
            print "connected to server at", sender
            self.connected = True
            for name, vars in msg.iteritems():
                Object(name, fromServer = True).vars.update(vars)
                
    def makeObjectName(self, name):
        self.send("makeObjectName",name)
        self.wait(lambda: self.send("makeObjectName",name), lambda: not self.objectNames.get(name))
        return self.objectNames[name].pop()
        
    def receive_objectName(self, msg, sender):
        name, realName = msg
        self.objectNames.setdefault(name,[]).append(realName)
        
    def receive_makeObject(self, msg, sender):
        Object(msg, fromServer = True)
        
    def deleteObject(self, name):
        self.send("deleteObject",name)
        
    def receive_deleteObject(self, msg, sender):
        Object.deleteObject(msg,False)
        
    def setVar(self, objectName, varName, val):
        self.send("setVar",(objectName,varName,val))
        
    def distSetVar(self, objectName, varName, val):
        self.send("distSetVar",(objectName,varName,val))
        
    def requestVar(self, objectName, varName):
        if (objectName, varName) not in self.requestedVars:
            self.send("requestVar",(objectName,varName))
            
    def receive_requestVarAck(self, msg, sender):
        self.requestedVars.add(msg)
        
    def receive_setVar(self, msg, sender):
        objectName, varName, val = msg
        Object.getObject(objectName).vars[varName] = val
        
    def runAction(self, objectName, actionType, actionName, args):
        def send():
            self.send("runAction",(objectName,actionType,actionName,args))
        send()
        self.wait(send,lambda: not self.actionNames.get((objectName,actionType,actionName)))
        return self.actionNames[(objectName,actionType,actionName)].pop()
        
    def receive_actionName(self, msg, sender):
        objectName, actionType, requestedName, actionName = msg
        self.actionNames.setdefault((objectName,actionType,requestedName),[]).append(actionName)
        
    def receive_runAction(self, msg, sender):
        objectName, actionType, actionName, args = msg
        Object.getObject(objectName).doRunAction(actionType,actionName,args)
        
    def publish(self, cmd, args):
        self.send("publish",(cmd,args))
        
    def subscribe(self, cmd):
        self.send("subscribe",cmd)
        
    def unsubscribe(self, cmd):
        self.send("unsubscribe",cmd)
        
    def receive_publish(self, msg, sender):
        cmd, args = msg
        eventServer.localPublish(cmd,**args)
        
    def rpc(self, objectName, actionName, cmd, args):
        def send():
            self.send("rpc",(objectName,actionName,cmd,args))
        send()
        def waitForRpcResult():
            self.wait(send, lambda: not self.rpcResults.get((objectName,actionName,cmd)))
            return self.rpcResults[(objectName,actionName,cmd)].pop()
        return waitForRpcResult
        
    def receive_rpcResult(self, msg, sender):
        objectName, actionName, cmd, result = msg
        self.rpcResults.setdefault((objectName,actionName,cmd),[]).append(result)
        
    def receive_rpc(self, msg, sender):
        objectName, actionName, cmd, args = msg
        object = Object.getObject(objectName)
        action = object.getAction(actionName)
        assert cmd in action.receiveFunctions, "action %s doesn't run %s" % (actionName,cmd)
        result = action.receiveFunctions[cmd](args)
        self.send("rpcResult",(objectName,actionName,cmd,result))
        
networkServer = NetworkServer()
